//****************************************************************************************************************
// Filename: documentwidget.cpp
// implemetation for  documentwidget class
// data March 2012
//****************************************************************************************************************

#include <QtGui>
#include <poppler-qt4.h>
#include "documentwidget.h"
#include <QItemDelegate>
#include <iostream>

DocumentWidget::DocumentWidget(QWidget *parent) : QListWidget(parent)
{
   // init
   currentPage = -1;
   doc = 0;
   scaleFactor = 1.0;
   // disable selection , this NOT going to disable mouse click 
   setSelectionMode(QAbstractItemView::NoSelection);
   setVerticalScrollMode (QAbstractItemView::ScrollPerPixel);
   // set color
   setStyleSheet("background: rgb(127, 127, 127)");  
   // set scrollBar   
   scrollBar = new QScrollBar(Qt::Vertical,this);
   scrollBar->setTracking(true);
   setVerticalScrollBar(scrollBar);
   connect(scrollBar,SIGNAL(valueChanged(int)),this,SLOT( scrollBarChangeHandler(int)));
   
   startTest = false;
   //enable mouse tracking
   setMouseTracking(true);

}


DocumentWidget::~DocumentWidget()
{
   if(doc != NULL)
      delete doc;
}

//function thar return *doce
Poppler::Document* DocumentWidget::getDoc()
{
    return doc;
}
//functin that return a vector of page
QVector<QImage>  DocumentWidget::getPages()
{
    return pages;
}
// return page number
// if no page return 0
int DocumentWidget::numPages()
{
  int rev = 0;
  if(doc)
    rev = doc -> numPages();
  return rev;
}
/*functions to return testing datas */ 
double DocumentWidget::getDistance()
{
   return  travelDistance;
}

int DocumentWidget::getDegree()
{
   return numDegrees;
}

int DocumentWidget::getEDegree()
{
   return eNumDegrees;
}

int DocumentWidget::getUpKey()
{
   return upkey;
}

int DocumentWidget::getDownKey()
{
   return downkey;
}
int DocumentWidget::getPageUpKey()
{
   return pageupkey;
}

int DocumentWidget::getPageDownKey()
{
   return pagedownkey;
}

// function to handle key press
void  DocumentWidget::keyPressEvent ( QKeyEvent * event)
{
   // move step size
   int delta = 20;
   // key Up
   if(event->key() == Qt::Key_Up)
   {
   
      
      int moveTo = scrollBar->value()- delta;
      if(moveTo < scrollBar-> minimum())
	 moveTo = scrollBar -> minimum();
      scrollBar->setValue(moveTo);
      if(startTest)
	 upkey++;
   
   }
   // key Down
   else if(event->key() == Qt::Key_Down)
   {
      int moveTo = scrollBar->value()+ delta;
      if(moveTo > scrollBar-> maximum())
	 moveTo = scrollBar -> maximum();
      scrollBar->setValue(moveTo);
      if(startTest)
	 downkey++;
      
   }
   //Key Page Up
   else if(event->key() == Qt::Key_PageUp)
   {
      if(currentPage > 0)
      {
	 currentPage --;
	 scrollBar->setValue(positions[currentPage]);
	 emit pageChanged(currentPage+1);
      }
      if(startTest)
	 pageupkey++;
   }
   //Key Page Down
   else if(event->key() == Qt::Key_PageDown)
   {
      
      if(currentPage < doc->numPages()-1)
      {
	 currentPage ++;
	 scrollBar->setValue(positions[currentPage]);
	 emit pageChanged(currentPage+1);
      }
      if(startTest)
	 pagedownkey++;
   }
}

// this function will traking all the wheel rotation
void DocumentWidget::wheelEvent (QWheelEvent * event)
{
   if(startTest)
   {
      int d = event->delta() / 8;
      if(d < 0)
	 d = -d;
      numDegrees += d;
      if(scrollBar->value() != scrollBar->maximum() && scrollBar->value() != scrollBar-> minimum())
      {
	 int d = event->delta() / 8;
	 if(d < 0)
	    d = -d;
	 eNumDegrees += d;
      }
   }
   QListWidget::wheelEvent(event);
}

// if mouse moved track distance
void DocumentWidget::mouseMoveEvent (QMouseEvent *event)
{
   // track mouse move distance 
   if(startTest)
   {
      if(last == QPointF(-1,-1))
	 last = event->globalPos();
      else
      {
	 QPointF current = event->globalPos();
	 QLineF line(last,current);
	 travelDistance += line.length();
	 last = current;
      }
   }
}

//a function to prevent QListWigdet's key press event
void  DocumentWidget::mousePressEvent (QMouseEvent * )
{
   // fake function :)
}

// event filter to filt mouse move event on child widget
bool  DocumentWidget::eventFilter(QObject *obj, QEvent *event)
{
   if(startTest && event->type() == QEvent::MouseMove)
   {

      QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
      if(last == QPointF(-1,-1))
	 last = mouseEvent->globalPos();
      else
      {
	 QPointF current = mouseEvent->globalPos();
	 QLineF line(last,current);
	 travelDistance += line.length();
	 last = current;
      }
      return true;
   }
   else
      return QObject::eventFilter(obj, event);
}

//Function handle double click event
//Because we use upper bondry to check which page we at
//where a double click happen , mouse maynot always on top of current page
//so we have to check of the pages behind the current page to make sure where is mouse click
void DocumentWidget::mouseDoubleClickEvent(QMouseEvent * e)
{
   if(startTest && e->button() == Qt::LeftButton)
   {
      QCursor cursor;
      QPoint p = mapFromGlobal(cursor.pos());
      int l = p.y() + scrollBar->value();
      
      for(int i = currentPage ; i < positions.size() ; ++i)
      {
	 if(l < positions[i+1] && l > positions[i])
	 {
	    emit pageClicked(i+1);
	 
	    break;
	 }
      }
   }
}

//Function handle resize event
void  DocumentWidget::resizeEvent ( QResizeEvent *e)
{
   if(scaleFactor < 0 && e->oldSize().height() != e->size().height())
      setScale(-1);
   QListWidget::resizeEvent(e);

}

// function to read document
bool DocumentWidget::setDocument(const QString &filePath)
{
   if(doc != NULL)
      delete doc;
   doc = Poppler::Document::load(filePath);
   if (doc) {
      
      doc->setRenderHint(Poppler::Document::Antialiasing);
      doc->setRenderHint(Poppler::Document::TextAntialiasing);
      currentPage = -1;
      clear();
      pages.clear();
      
      //redo page by page
      for(int i = 0 ; i < doc->numPages() ; ++i)
      {
	 QImage image = doc->page(i) ->renderToImage(1.0* physicalDpiX(),1.0 * physicalDpiY());
	 pages.push_back(image);
      }
      //set to first page
      currentPage = 0;
      // set to fit windows mode
      setScale(-1);
   }
   return doc != 0;
}

// set page slot
void DocumentWidget::setPage(int page)
{
   if (page != currentPage + 1) {
      showPage(page);
  
    }
}

void DocumentWidget::setScale(qreal scale)
{

   if (scaleFactor != scale) {
      if(scale > 0 )
	 scaleFactor = scale;
      
      clear();
       
      positions.clear();
      int pos = 0;
      positions.push_back(-1);
      

      for(int i = 0 ; i < pages.size() ; ++i)
      {
	 // compute image
	 QImage image = pages[i];
	 
	 int w =(int)(scaleFactor *(double)image.width());
	 int h =(int)(scaleFactor*(double)image.height());
	 // if fit window mode
	 if(scale < 0)
	 {
	    double ratio = (double)image.width() /(double)image.height();
	    h = height();
	    w = (int)(ratio *(double) h);
	 }
	 if(h != image.height())
	    image = image.scaled(w,h,Qt::IgnoreAspectRatio,Qt::SmoothTransformation);

	 // put image into Qlabel
	 QSize size(image.size());
	 size.setHeight(size.height()+2);
	 current = new QLabel(this);
	 current->setMouseTracking(true);
	 current->installEventFilter(this);
	 current->setAlignment(Qt::AlignCenter);
	 current->setPixmap(QPixmap::fromImage(image));
	 QListWidgetItem * WidgetItem = new QListWidgetItem;
	 //add into list widget
	 WidgetItem -> setSizeHint(size);
	 addItem(WidgetItem);
	 setItemWidget(WidgetItem,current);
	 // update position vector
	 pos +=  size.height();
	 positions.push_back(pos);
      }
      updateGeometry();
      setPage(currentPage);
      if(scale == -1)
	 scaleFactor = -2; // for auto fit window 
      showPage();
   }
   
}
//function to start collect data
void DocumentWidget::beginTest()
{
   startTest = true;
   travelDistance = 0.0;
   numDegrees = 0;
   eNumDegrees = 0;

   upkey = 0;
   downkey = 0;
   pageupkey = 0;
   pagedownkey = 0;
    
   
   last.setX(-1);
   last.setY(-1);
}

// function to abort testing
void DocumentWidget::abortTest()
{
    startTest = false;
}

// function to handle scroll bar value change
void DocumentWidget::scrollBarChangeHandler(int value)
{
   // check if current page move forward
   if(value < positions[currentPage])
   {
      currentPage --;
      emit pageChanged(currentPage+1);
   }
   // or move back backward
   else if(value >= positions[currentPage+1])
   {
      currentPage ++;
      emit pageChanged(currentPage+1);
   }
}
// function to show page
void DocumentWidget::showPage(int page)
{
   
   if(page > 0 && page < doc->numPages()+1 && page != currentPage + 1)
   {
      currentPage = page - 1;
      setCurrentItem (item(page-1));
      emit pageChanged(page);
            
   }
}
